#ifndef SCHEDULER_H
#define SCHEDULER_H

#include "process.h"
#include <algorithm>
#include <deque>
#include <iostream>
#include <queue>

using namespace std;

class Scheduler {
protected:
  int preemptionTime;
  std::vector<Process *> runqueue;
  std::vector<Process *> expiredqueue;
  int quantum;

public:
  Scheduler(int preemptionTime = 10000) : preemptionTime(preemptionTime) {}

  virtual void add_process(Process *p) = 0;

  virtual Process *get_next_process() = 0;

  virtual bool preemptive() const { return preemptionTime < 10000; }

  bool empty();

  int get_quantum();

  void print_info();
};

class FCFS : public Scheduler {
public:
  void add_process(Process *proc) override;

  Process *get_next_process() override;
};

class LCFS : public Scheduler {
  Process *get_next_process();

  void add_process(Process *proc);

  int get_quantum();
};

class RR : public Scheduler {
public:
  // 添加进程到队列
  void add_process(Process *proc) override { runqueue.push_back(proc); }

  // 获取下一个进程
  Process *get_next_process() override {
    if (runqueue.empty()) {
      return nullptr;
    }
    Process *next_process = runqueue.front();
    runqueue.erase(runqueue.begin());
    return next_process;
  }
};

class PRIO : public Scheduler {
public:
  void add_expired(Process *proc);

  void add_process(Process *proc);

  void add_active(Process *proc);

  bool not_empty();

  Process *get_next_process();

  bool goes_after(Process *p1, Process *p2);
};

class SJF : public Scheduler {
private:
  // 比较函数，用于比较两个进程的运行时间
  struct Compare {
    bool operator()(Process *p1, Process *p2) {
      return p1->get_cpu_burst() > p2->get_cpu_burst();
    }
  };

  // 用于保存进程的优先队列，根据进程的运行时间排序
  std::priority_queue<Process *, std::vector<Process *>, Compare> processes;

public:
  SJF() {}

  // 添加进程到队列
  void add_process(Process *proc) override { processes.push(proc); }

  // 获取下一个进程
  Process *get_next_process() override {
    if (!processes.empty()) {
      Process *next = processes.top();
      processes.pop();
      return next;
    }
    return nullptr;
  }
};

class SRTF : public Scheduler {
private:
  // 比较函数，用于比较两个进程的剩余运行时间
  struct Compare {
    bool operator()(Process *p1, Process *p2) {
      return p1->get_remaining_time() > p2->get_remaining_time();
    }
  };

  // 用于保存进程的优先队列，根据进程的剩余运行时间排序
  std::priority_queue<Process *, std::vector<Process *>, Compare> processes;

public:
  // 添加进程到队列
  void add_process(Process *proc) override { processes.push(proc); }

  // 获取下一个进程
  Process *get_next_process() override {
    if (!processes.empty()) {
      Process *next = processes.top();
      processes.pop();
      return next;
    }
    return nullptr;
  }
};

class PREPRIO : public Scheduler {
private:
  int maxPriority;                                  // Maximum priority level
  std::vector<std::deque<Process *>> activeQueues;  // Active queues
  std::vector<std::deque<Process *>> expiredQueues; // Expired queues

public:
  PREPRIO(int maxPriority = 4) : maxPriority(maxPriority) {
    activeQueues.resize(maxPriority + 1);
    expiredQueues.resize(maxPriority + 1);
  }

  // Add a process to the expired queue
  void add_expired(Process *proc) {
    int priority = proc->get_priority();
    expiredQueues[priority].push_back(proc);
  }

  // Add a process to the appropriate active queue
  void add_process(Process *proc) override {
    int priority = proc->get_priority();
    activeQueues[priority].push_back(proc);
  }

  // Add a process to the appropriate active or expired queue based on its
  // remaining time
  void add_active(Process *proc) {
    if (proc->get_remaining_time() <= preemptionTime) {
      add_process(proc);
    } else {
      add_expired(proc);
    }
  }

  // Check if any queue is not empty
  bool not_empty() {
    for (int i = 0; i <= maxPriority; ++i) {
      if (!activeQueues[i].empty() || !expiredQueues[i].empty()) {
        return true;
      }
    }
    return false;
  }

  // Determine if process p1 goes after process p2
  bool goes_after(Process *p1, Process *p2) {
    return p1->get_priority() < p2->get_priority();
  }

  // Get the next process to run
  Process *get_next_process() override {
    for (int i = 0; i <= maxPriority; ++i) {
      if (!activeQueues[i].empty()) {
        Process *next_process = activeQueues[i].front();
        activeQueues[i].pop_front();
        return next_process;
      }
    }

    // If no active process, swap active and expired queues
    activeQueues.swap(expiredQueues);

    for (int i = 0; i <= maxPriority; ++i) {
      if (!activeQueues[i].empty()) {
        Process *next_process = activeQueues[i].front();
        activeQueues[i].pop_front();
        return next_process;
      }
    }

    return nullptr; // No process available
  }
};

#endif // SCHEDULER_H
